package com.ruoyi.system.service.impl;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.system.mapper.SyncFileSyncMapper;
import com.ruoyi.system.mapper.SyncFileSyncLogMapper;
import com.ruoyi.system.domain.datasync.SyncFileSync;
import com.ruoyi.system.domain.datasync.SyncFileSyncLog;
import com.ruoyi.system.service.ISyncFileSyncService;
import com.ruoyi.system.service.ISyncServerService;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;

/**
 * 文件同步Service业务层处理
 * 
 * @author ruoyi
 */
@Service
public class SyncFileSyncServiceImpl implements ISyncFileSyncService 
{
    private static final Logger log = LoggerFactory.getLogger(SyncFileSyncServiceImpl.class);
    
    @Autowired
    private SyncFileSyncMapper syncFileSyncMapper;
    
    @Autowired
    private SyncFileSyncLogMapper syncFileSyncLogMapper;
    
    @Autowired
    private ISyncServerService syncServerService;

    /**
     * 查询文件同步
     * 
     * @param taskId 文件同步主键
     * @return 文件同步
     */
    @Override
    public SyncFileSync selectSyncFileSyncByTaskId(Long taskId)
    {
        log.info("查询文件同步任务: taskId={}", taskId);
        SyncFileSync result = syncFileSyncMapper.selectSyncFileSyncByTaskId(taskId);
        log.info("查询文件同步任务结果: {}", result != null ? "成功" : "未找到记录");
        return result;
    }

    /**
     * 查询文件同步列表
     * 
     * @param syncFileSync 文件同步
     * @return 文件同步
     */
    @Override
    public List<SyncFileSync> selectSyncFileSyncList(SyncFileSync syncFileSync)
    {
        log.info("查询文件同步列表: 参数={}", syncFileSync != null ? syncFileSync.toString() : "null");
        List<SyncFileSync> list = syncFileSyncMapper.selectSyncFileSyncList(syncFileSync);
        log.info("查询文件同步列表结果: 获取记录数={}", list != null ? list.size() : 0);
        return list;
    }

    /**
     * 新增文件同步
     * 
     * @param syncFileSync 文件同步
     * @return 结果
     */
    @Override
    public int insertSyncFileSync(SyncFileSync syncFileSync)
    {
        log.info("新增文件同步任务: {}", syncFileSync);
        syncFileSync.setCreateTime(DateUtils.getNowDate());
        int rows = syncFileSyncMapper.insertSyncFileSync(syncFileSync);
        log.info("新增文件同步任务结果: 影响行数={}, 新任务ID={}", rows, syncFileSync.getTaskId());
        return rows;
    }

    /**
     * 修改文件同步
     * 
     * @param syncFileSync 文件同步
     * @return 结果
     */
    @Override
    public int updateSyncFileSync(SyncFileSync syncFileSync)
    {
        log.info("修改文件同步任务: taskId={}", syncFileSync.getTaskId());
        syncFileSync.setUpdateTime(DateUtils.getNowDate());
        int rows = syncFileSyncMapper.updateSyncFileSync(syncFileSync);
        log.info("修改文件同步任务结果: 影响行数={}", rows);
        return rows;
    }

    /**
     * 批量删除文件同步
     * 
     * @param taskIds 需要删除的文件同步主键
     * @return 结果
     */
    @Override
    public int deleteSyncFileSyncByTaskIds(Long[] taskIds)
    {
        log.info("批量删除文件同步任务: taskIds={}", taskIds);
        // 同时删除关联的日志记录
        for (Long taskId : taskIds) {
            syncFileSyncLogMapper.deleteSyncFileSyncLogByTaskId(taskId);
        }
        int rows = syncFileSyncMapper.deleteSyncFileSyncByTaskIds(taskIds);
        log.info("批量删除文件同步任务结果: 影响行数={}", rows);
        return rows;
    }

    /**
     * 删除文件同步信息
     * 
     * @param taskId 文件同步主键
     * @return 结果
     */
    @Override
    public int deleteSyncFileSyncByTaskId(Long taskId)
    {
        log.info("删除文件同步任务: taskId={}", taskId);
        // 同时删除关联的日志记录
        syncFileSyncLogMapper.deleteSyncFileSyncLogByTaskId(taskId);
        int rows = syncFileSyncMapper.deleteSyncFileSyncByTaskId(taskId);
        log.info("删除文件同步任务结果: 影响行数={}", rows);
        return rows;
    }
    
    /**
     * 执行文件同步任务
     * 
     * @param taskId 文件同步任务ID
     * @return 结果
     */
    @Override
    public String runSyncFileTask(Long taskId)
    {
        log.info("开始执行文件同步任务: taskId={}", taskId);
        
        // 获取文件同步任务信息
        SyncFileSync syncTask = syncFileSyncMapper.selectSyncFileSyncByTaskId(taskId);
        if (syncTask == null)
        {
            log.error("执行文件同步任务失败: 任务不存在, taskId={}", taskId);
            return "任务不存在";
        }
        
        log.info("获取同步任务信息: taskName={}, sourceServerId={}, targetServerId={}, syncType={}", 
                syncTask.getTaskName(), syncTask.getSourceServerId(), syncTask.getTargetServerId(), syncTask.getSyncType());
        
        // 创建日志记录
        SyncFileSyncLog syncLog = new SyncFileSyncLog();
        syncLog.setTaskId(taskId);
        syncLog.setTaskName(syncTask.getTaskName());
        syncLog.setSourceServerId(syncTask.getSourceServerId());
        syncLog.setSourceServerName(syncTask.getSourceServerName());
        syncLog.setTargetServerId(syncTask.getTargetServerId());
        syncLog.setTargetServerName(syncTask.getTargetServerName());
        syncLog.setSyncType(syncTask.getSyncType());
        syncLog.setStartTime(new Date());
        syncLog.setCreateTime(new Date());
        syncLog.setCreateBy(SecurityUtils.getUsername());
        
        try {
            // 更新最近执行时间
            String execTime = DateUtils.getTime();
            syncTask.setLastExecTime(execTime);
            log.info("更新同步任务最近执行时间: lastExecTime={}", execTime);
            syncFileSyncMapper.updateSyncFileSync(syncTask);
            
            // 根据同步类型执行全量同步或增量同步
            String syncType = syncTask.getSyncType();
            String result;
            
            if ("1".equals(syncType))
            {
                log.info("执行全量文件同步: taskId={}, taskName={}", taskId, syncTask.getTaskName());
                result = executeFullSync(syncTask, syncLog);
            }
            else if ("2".equals(syncType))
            {
                log.info("执行增量文件同步: taskId={}, taskName={}", taskId, syncTask.getTaskName());
                result = executeIncrementalSync(syncTask, syncLog);
            }
            else
            {
                log.error("未知的同步类型: syncType={}", syncType);
                result = "未知的同步类型";
                syncLog.setStatus("1"); // 失败
                syncLog.setErrorInfo("未知的同步类型: " + syncType);
            }
            
            // 更新日志记录
            syncLog.setEndTime(new Date());
            syncLog.setDuration((int)((syncLog.getEndTime().getTime() - syncLog.getStartTime().getTime()) / 1000));
            if (syncLog.getStatus() == null) {
                syncLog.setStatus("0"); // 成功
            }
            syncFileSyncLogMapper.insertSyncFileSyncLog(syncLog);
            
            log.info("文件同步任务执行完成: taskId={}, logId={}, result={}", taskId, syncLog.getLogId(), result);
            return result;
        } catch (Exception e) {
            log.error("文件同步执行异常: taskId={}, error={}", taskId, e.getMessage(), e);
            
            // 记录异常日志
            syncLog.setEndTime(new Date());
            syncLog.setDuration((int)((syncLog.getEndTime().getTime() - syncLog.getStartTime().getTime()) / 1000));
            syncLog.setStatus("1"); // 失败
            syncLog.setErrorInfo(e.getMessage());
            syncFileSyncLogMapper.insertSyncFileSyncLog(syncLog);
            
            return "同步失败: " + e.getMessage();
        }
    }
    
    /**
     * 执行全量文件同步
     * 
     * @param syncTask 同步任务
     * @param syncLog 日志记录
     * @return 结果
     */
    private String executeFullSync(SyncFileSync syncTask, SyncFileSyncLog syncLog)
    {
        log.info("开始全量文件同步: taskName={}, sourcePath={}, targetPath={}", 
                syncTask.getTaskName(), syncTask.getSourcePath(), syncTask.getTargetPath());
        
        try {
            // 调用服务器服务进行文件同步
            Map<String, Object> result = syncServerService.syncFileBetweenServers(
                syncTask.getSourceServerId(), 
                syncTask.getTargetServerId(), 
                syncTask.getSourcePath(), 
                syncTask.getTargetPath()
            );
            
            boolean success = Boolean.TRUE.equals(result.get("success"));
            if (!success) {
                String errorMsg = (String) result.get("message");
                syncLog.setStatus("1"); // 失败
                syncLog.setErrorInfo(errorMsg);
                log.error("全量同步失败: taskId={}, error={}", syncTask.getTaskId(), errorMsg);
                return "同步失败: " + errorMsg;
            }
            
            // 根据同步结果类型处理结果
            String syncType = (String) result.get("type");
            int fileCount = 0;
            long totalSize = 0;
            
            if ("directory".equals(syncType)) {
                // 目录同步
                List<Map<String, Object>> files = (List<Map<String, Object>>) result.get("files");
                if (files != null) {
                    fileCount = files.size();
                    int successCount = 0;
                    
                    for (Map<String, Object> file : files) {
                        if (Boolean.TRUE.equals(file.get("success"))) {
                            successCount++;
                            // 尝试统计文件大小
                            Object sizeObj = file.get("size");
                            if (sizeObj != null) {
                                try {
                                    totalSize += Long.parseLong(sizeObj.toString());
                                } catch (NumberFormatException e) {
                                    // 忽略转换异常
                                }
                            }
                        }
                    }
                    
                    syncLog.setFileCount(fileCount);
                    syncLog.setTotalSize(totalSize);
                    
                    log.info("全量目录同步完成: taskId={}, 共{}个文件, 成功{}个, 总大小={}字节", 
                            syncTask.getTaskId(), fileCount, successCount, totalSize);
                    
                    return String.format("全量同步执行完成: 共%d个文件, 成功同步%d个, 总大小%s", 
                            fileCount, successCount, formatFileSize(totalSize));
                }
            } else {
                // 单文件同步
                fileCount = 1;
                // 尝试获取文件大小
                Object sizeObj = result.get("size");
                if (sizeObj != null) {
                    try {
                        totalSize = Long.parseLong(sizeObj.toString());
                    } catch (NumberFormatException e) {
                        // 忽略转换异常
                    }
                }
                
                syncLog.setFileCount(fileCount);
                syncLog.setTotalSize(totalSize);
                
                log.info("全量文件同步完成: taskId={}, 文件大小={}字节", 
                        syncTask.getTaskId(), totalSize);
                
                return String.format("全量同步执行完成: 文件同步成功, 大小%s", formatFileSize(totalSize));
            }
            
            // 默认结果
            syncLog.setFileCount(fileCount);
            syncLog.setTotalSize(totalSize);
            return "全量同步执行完成";
            
        } catch (Exception e) {
            log.error("全量同步过程中发生异常: taskId={}, error={}", syncTask.getTaskId(), e.getMessage(), e);
            syncLog.setStatus("1"); // 失败
            syncLog.setErrorInfo(e.getMessage());
            return "同步失败: " + e.getMessage();
        }
    }
    
    /**
     * 执行增量文件同步
     * 
     * @param syncTask 同步任务
     * @param syncLog 日志记录
     * @return 结果
     */
    private String executeIncrementalSync(SyncFileSync syncTask, SyncFileSyncLog syncLog)
    {
        log.info("开始增量文件同步: taskName={}, sourcePath={}, targetPath={}", 
                syncTask.getTaskName(), syncTask.getSourcePath(), syncTask.getTargetPath());
        
        try {
            // 获取上次同步时间
            String lastExecTime = syncTask.getLastExecTime();
            Date lastSyncTime = null;
            if (lastExecTime != null && !lastExecTime.isEmpty()) {
                try {
                    lastSyncTime = DateUtils.parseDate(lastExecTime);
                } catch (Exception e) {
                    log.warn("解析上次同步时间失败: {}", lastExecTime);
                }
            }
            
            // 如果没有上次同步时间或解析失败，执行全量同步
            if (lastSyncTime == null) {
                log.info("无有效的上次同步时间，执行全量同步: taskId={}", syncTask.getTaskId());
                return executeFullSync(syncTask, syncLog);
            }
            
            // 查找上次同步后修改的文件
            String findChangedFilesCommand = String.format(
                "find \"%s\" -type f -newermt \"%s\" | sort",
                syncTask.getSourcePath(),
                DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, lastSyncTime)
            );
            
            Long sourceServerId = syncTask.getSourceServerId();
            Map<String, Object> cmdResult = syncServerService.executeCommand(sourceServerId, findChangedFilesCommand);
            
            if (!Boolean.TRUE.equals(cmdResult.get("success"))) {
                String errorMsg = (String) cmdResult.get("stderr");
                syncLog.setStatus("1"); // 失败
                syncLog.setErrorInfo("查找变更文件失败: " + errorMsg);
                log.error("增量同步查找变更文件失败: taskId={}, error={}", syncTask.getTaskId(), errorMsg);
                return "增量同步失败: 查找变更文件失败 - " + errorMsg;
            }
            
            String changedFilesOutput = (String) cmdResult.get("stdout");
            String[] changedFiles = changedFilesOutput.split("\\n");
            
            // 过滤掉空行
            List<String> filesToSync = new ArrayList<>();
            for (String file : changedFiles) {
                if (file != null && !file.trim().isEmpty()) {
                    filesToSync.add(file.trim());
                }
            }
            
            if (filesToSync.isEmpty()) {
                log.info("增量同步未发现变更文件: taskId={}", syncTask.getTaskId());
                syncLog.setFileCount(0);
                syncLog.setTotalSize(0L);
                return "增量同步完成: 未发现需要同步的文件";
            }
            
            log.info("增量同步发现{}个变更文件: taskId={}", filesToSync.size(), syncTask.getTaskId());
            
            // 同步每个变更文件
            int successCount = 0;
            long totalSize = 0;
            List<String> errors = new ArrayList<>();
            
            for (String sourceFilePath : filesToSync) {
                // 计算目标文件路径
                String relativePath = sourceFilePath.substring(syncTask.getSourcePath().length());
                if (relativePath.startsWith("/")) {
                    relativePath = relativePath.substring(1);
                }
                
                String targetFilePath = syncTask.getTargetPath();
                if (!targetFilePath.endsWith("/")) {
                    targetFilePath += "/";
                }
                targetFilePath += relativePath;
                
                // 确保目标目录存在
                String targetDir = targetFilePath.substring(0, targetFilePath.lastIndexOf("/"));
                syncServerService.executeCommand(syncTask.getTargetServerId(), "mkdir -p \"" + targetDir + "\"");
                
                // 同步文件
                Map<String, Object> fileResult = syncServerService.syncFileBetweenServers(
                    syncTask.getSourceServerId(),
                    syncTask.getTargetServerId(),
                    sourceFilePath,
                    targetFilePath
                );
                
                if (Boolean.TRUE.equals(fileResult.get("success"))) {
                    successCount++;
                    // 尝试获取文件大小
                    Object sizeObj = fileResult.get("size");
                    if (sizeObj != null) {
                        try {
                            totalSize += Long.parseLong(sizeObj.toString());
                        } catch (NumberFormatException e) {
                            // 忽略转换异常
                        }
                    }
                } else {
                    String error = "文件 " + sourceFilePath + " 同步失败: " + fileResult.get("message");
                    errors.add(error);
                    log.error("增量同步文件失败: taskId={}, {}", syncTask.getTaskId(), error);
                }
            }
            
            // 记录同步结果
            syncLog.setFileCount(filesToSync.size());
            syncLog.setTotalSize(totalSize);
            
            if (!errors.isEmpty()) {
                // 有同步失败的文件
                syncLog.setStatus("1"); // 部分失败
                syncLog.setErrorInfo(String.join("\n", errors));
            }
            
            log.info("增量同步完成: taskId={}, 共{}个文件, 成功{}个, 总大小={}字节", 
                    syncTask.getTaskId(), filesToSync.size(), successCount, totalSize);
            
            return String.format("增量同步执行完成: 共%d个文件, 成功同步%d个, 总大小%s", 
                    filesToSync.size(), successCount, formatFileSize(totalSize));
            
        } catch (Exception e) {
            log.error("增量同步过程中发生异常: taskId={}, error={}", syncTask.getTaskId(), e.getMessage(), e);
            syncLog.setStatus("1"); // 失败
            syncLog.setErrorInfo(e.getMessage());
            return "同步失败: " + e.getMessage();
        }
    }

    /**
     * 查询文件同步日志列表
     * 
     * @param taskId 文件同步任务ID
     * @return 日志列表
     */
    @Override
    public List<SyncFileSyncLog> selectSyncFileSyncLogsByTaskId(Long taskId) {
        log.info("查询文件同步日志列表: taskId={}", taskId);
        List<SyncFileSyncLog> logs = syncFileSyncLogMapper.selectSyncFileSyncLogByTaskId(taskId);
        log.info("查询文件同步日志列表结果: 共{}条记录", logs.size());
        return logs;
    }
    
    /**
     * 获取同步日志详情
     * 
     * @param logId 日志ID
     * @return 日志详情
     */
    @Override
    public String getSyncFileSyncLogDetail(Long logId) {
        log.info("获取同步日志详情: logId={}", logId);
        SyncFileSyncLog log = syncFileSyncLogMapper.selectSyncFileSyncLogByLogId(logId);
        
        if (log == null) {
            return "日志不存在";
        }
        
        // 构建日志详情
        StringBuilder detail = new StringBuilder();
        detail.append("任务名称: ").append(log.getTaskName()).append("\n\n");
        detail.append("开始时间: ").append(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, log.getStartTime())).append("\n");
        detail.append("结束时间: ").append(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, log.getEndTime())).append("\n");
        detail.append("耗时: ").append(log.getDuration()).append("秒\n\n");
        detail.append("源服务器: ").append(log.getSourceServerName()).append("\n");
        detail.append("目标服务器: ").append(log.getTargetServerName()).append("\n\n");
        detail.append("同步文件数: ").append(log.getFileCount()).append("\n");
        detail.append("总大小: ").append(formatFileSize(log.getTotalSize())).append("\n\n");
        detail.append("执行状态: ").append("0".equals(log.getStatus()) ? "成功" : "失败").append("\n");
        
        if (log.getErrorInfo() != null && !log.getErrorInfo().isEmpty()) {
            detail.append("\n错误信息:\n").append(log.getErrorInfo());
        }
        
        if (log.getRemark() != null && !log.getRemark().isEmpty()) {
            detail.append("\n\n备注:\n").append(log.getRemark());
        }
        
        return detail.toString();
    }
    
    /**
     * 格式化文件大小
     */
    private String formatFileSize(Long size) {
        if (size == null) {
            return "0 B";
        }
        
        if (size < 1024) {
            return size + " B";
        } else if (size < 1024 * 1024) {
            return String.format("%.2f KB", size / 1024.0);
        } else if (size < 1024 * 1024 * 1024) {
            return String.format("%.2f MB", size / (1024.0 * 1024));
        } else {
            return String.format("%.2f GB", size / (1024.0 * 1024 * 1024));
        }
    }
} 